#include "gameroom.h"
#include "gameselect.h"
#include "gamehall.h"
#include <QTimer>
GameRoom::GameRoom(QWidget *parent) : QWidget(parent)
{
    this->setFixedSize(1200,900);
    this->setWindowIcon(QIcon(":res/ico.png"));
    this->setWindowTitle("贪吃蛇大作战");

    /* 定义开始游戏时 的变量
     * 比如我们我们需要使用定时器去执行 蛇的移动速度 */
    //初始化贪吃蛇
        snakeList.push_back(QRectF(this->width() * 0.5,this->height() * 0.5,ksnakeNodeWidth,ksnakeNodeHeight));
        moveUp();
        moveUp();

        //创建食物
        createNewFood();

        //定时器
        timer = new QTimer(this);
        connect(timer,&QTimer::timeout,[=](){
            int cnt = 1;                            // 定义一个计数器变量cnt并初始化为1。这个计数器用于控制蛇移动的次数

            /* 检查蛇头（snakeList.front()）是否与食物节点（foodNode）相交。如果相交，则表示蛇吃到了食物 */
            if(snakeList.front().intersects(foodNode))
            {
                createNewFood();                    //如果吃到食物，则生成新的食物节点
                ++cnt;                              // 吃到食物后，增加计数器cnt的值，以便让蛇多移动一次
                QSound::play(":res/eatfood.wav");   // 播放吃食物的音效
            }

            while(cnt--)                            // 移动蛇 就是 移动每个节点的位置 重新渲染一遍，让它看上去像是移动了的
            {
                /* 根据moveDirect变量的值，调用相应的移动函数（moveUp、moveDown、moveLeft或moveRight）来更新蛇的位置 */
                switch(moveDirect){
                case SnakeDirect::UP:
                    moveUp();
                    break;
                case SnakeDirect::DOWN:
                    moveDown();
                    break;
                case SnakeDirect::LEFT:
                    moveLeft();
                    break;
                case SnakeDirect::RIGHT:
                    moveRight();
                    break;
                default:
                    qDebug() << "非法移动方向";
                    break;
                }
            }

            /* snakeList.pop_back();: 在每次移动之后，移除蛇的最后一个节点（尾部），
             * 这样可以保持蛇的长度不变（除非吃到食物）。
             * 如果吃到食物，由于cnt增加了，会在下一次循环中多移动一次，从而增加蛇的长度。 */
            snakeList.pop_back();
            update();

        });

        // 开始游戏  暂停游戏
            QFont font("方正舒体",20);
            QPushButton *strBtn = new QPushButton(this);
            QPushButton *stopBtn = new QPushButton(this);

            strBtn->move(1030,280);
            stopBtn->move(1030,340);

            strBtn->setFont(font);
            stopBtn->setFont(font);

            strBtn->setText("开始游戏");
            stopBtn->setText("暂停游戏");

            sound = new QSound(":res/Trepak.wav");
            // 信号槽
            connect(strBtn,&QPushButton::clicked,[=](){
                //sound = new QSound(":res/Trepak.wav");
                sound->play();
                sound->setLoops(-1);

                isGameStart = true;
                timer->start(moveTimeout);

                qDebug() << " 游戏正常运行 ";

            });

            connect(stopBtn,&QPushButton::clicked,[=](){
                QSound::play(":res/clicked.wav");
                isGameStart = false;
                timer->stop();
                sound->stop();
                qDebug() << " 游戏暂停 ";
            });

            // 方向控制键
                QFont dfont("方正舒体",40);
                QPushButton *up = new QPushButton(this);
                QPushButton *down = new QPushButton(this);
                QPushButton *left = new QPushButton(this);
                QPushButton *right = new QPushButton(this);

                up->move(1070,470);
                down->move(1070,570);
                left->move(1030,520);
                right->move(1110,520);

                up->setFont(dfont);
                down->setFont(dfont);
                left->setFont(dfont);
                right->setFont(dfont);

                up->setText("↑");
                down->setText("↓");
                left->setText("←");
                right->setText("→");

                up->setStyleSheet("QPushButton{border:0px;}");
                down->setStyleSheet("QPushButton{border:0px;}");
                left->setStyleSheet("QPushButton{border:0px;}");
                right->setStyleSheet("QPushButton{border:0px;}");

                // 信号槽
                connect(up,&QPushButton::clicked,[=](){
                    if(moveDirect != SnakeDirect::DOWN)
                        moveDirect = SnakeDirect::UP;
                });
                connect(down,&QPushButton::clicked,[=](){
                    if(moveDirect != SnakeDirect::UP)
                        moveDirect = SnakeDirect::DOWN;
                });
                connect(left,&QPushButton::clicked,[=](){
                    if(moveDirect != SnakeDirect::RIGHT)
                        moveDirect = SnakeDirect::LEFT;
                });
                connect(right,&QPushButton::clicked,[=](){
                    if(moveDirect != SnakeDirect::LEFT)
                        moveDirect = SnakeDirect::RIGHT;
                });

    // 退出按钮
    // 退出游戏键
        QPushButton *exitBtn = new QPushButton(this);
        exitBtn->move(1030,800);
        exitBtn->setFont(font);
        exitBtn->setText("退出游戏");

        QMessageBox *msg = new QMessageBox(this);
        //msg->setWindowIcon(QIcon(":res/ico.png"));
        msg->setIcon(QMessageBox::Question);
        msg->setWindowTitle("退出游戏");
        msg->setText("是否退出游戏，返回上一界面？");

        QPushButton *ok = new QPushButton("ok");
        QPushButton *cancel = new QPushButton("cancel");

        msg->addButton(ok,QMessageBox::AcceptRole);
        msg->addButton(cancel,QMessageBox::RejectRole);

        connect(exitBtn,&QPushButton::clicked,[=](){
            QSound::play(":res/clicked.wav");
            // 弹出一个对话框
            msg->show();
            msg->exec();

            if(msg->clickedButton() == ok)
            {
                this->close();
                GameSelect *select = new GameSelect;
                select->show();
                select->setGeometry(this->geometry());
                QSound::play(":res/clicked.wav");
                qDebug() << " 退出游戏，返回上一界面 ";
                sound->stop();
                qDebug() << " 停止背景音乐 ";
            }
            else
            {
                QSound::play(":res/clicked.wav");
                qDebug() << " 返回 ";
                msg->close();
            }
        });



}

void GameRoom::paintEvent(QPaintEvent *event)
{
    // 绘图对象
    QPainter painter(this);
    QPixmap pix;

        /* 我们要考虑一下界面中会出现的物品  比如 左侧游戏草地， 右侧操作台按钮  蛇的出现  食物的出现  积分栏的出现 */
    /* ------------------------------------------------------------------------------------------------------------ */
    // 不同模式下的房间
    /*pix.load(":res/game_room.png");*/

    if(styleRoom == GameStyle::SIMPLE)
    {
        pix.load(":res/simple_room.png");
    }
    else if(styleRoom == GameStyle::NORMAL)
    {
        pix.load(":res/normal_room.png");
    }
    else if(styleRoom == GameStyle::COMPLEX)
    {
        pix.load(":res/hard_room.png");
    }
    painter.drawPixmap(0,0,1000,900,pix);


    // 右侧控制台
    pix.load(":res/bg1.png");
    painter.drawPixmap(1000,0,200,1000,pix);

    // 绘制蛇
        /* 我们在绘制蛇的时候，要了解蛇的组成  蛇头  蛇身  蛇尾 */
    /* ------------------------------------------------------------------------------------------------------------ */
        /* 蛇头 的绘制 ，我们要考虑蛇的行动方向，选择蛇头图片 这是就需要一些变量来描写蛇的属性 */
        /* 现在我们转到 .h 文件中 定义成员变量 */
    if(moveDirect == SnakeDirect::UP)
    {
        pix.load(":res/up.png");        // 读取蛇头向上的图片
    }
    else if(moveDirect == SnakeDirect::DOWN)
    {
        pix.load(":res/down.png");        // 读取蛇头向下的图片
    }
    else if(moveDirect == SnakeDirect::LEFT)
    {
        pix.load(":res/left.png");        // 读取蛇头向左的图片
    }
    else if(moveDirect == SnakeDirect::RIGHT)
    {
        pix.load(":res/right.png");        // 读取蛇头向右的图片
    }
    // 确定蛇头的位置 首先要定义一个结点指向蛇头位置  再放置到结点所在的位置
    auto snakeHead = snakeList.front();
    painter.drawPixmap(snakeHead.x(),snakeHead.y(),snakeHead.width(),snakeHead.height(),pix);


    // 蛇身
    pix.load(":res/Bd.png");
    for(int i = 1; i < snakeList.size() - 1; i++)
    {
        auto node = snakeList.at(i);
        painter.drawPixmap(node.x(),node.y(),node.width(),node.height(),pix);
    }

    // 蛇尾
    auto snakeTail = snakeList.back();
    painter.drawPixmap(snakeTail.x(),snakeTail.y(),snakeTail.width(),snakeTail.height(),pix);

    // 绘制食物
    if(styleRoom == GameStyle::SIMPLE)
    {
        pix.load(":res/simple_food.png");
    }
    else if(styleRoom == GameStyle::NORMAL)
    {
        pix.load(":res/normal_food.bmp");
    }
    else if(styleRoom == GameStyle::COMPLEX)
    {
        pix.load(":res/hard_food.png");
    }
    painter.drawPixmap(foodNode.x(),foodNode.y(),foodNode.width(),foodNode.height(),pix);


    // 绘制积分栏
    // 绘制分数
    pix.load(":res/sorce_bg.png");
    painter.drawPixmap(1050,100,100,50,pix);



    /* QPen直接绘制积分，它用于定义绘图的笔刷样式，包括线条的宽度、颜色、样式（如实线、虚线、点线等）以及端点和连接点的样式。*/
    QPen pen;
    pen.setColor(Qt::black);
    painter.setPen(pen);
    QFont qfont("楷体",30);
    painter.setFont(qfont);
    painter.drawText(this->width() * 0.92, this->height() * 0.16,
                        QString("%1").arg(snakeList.size()));
    /* QString("%1").arg(snakeList.size())是用来格式化字符串的。
     * 这里将snakeList.size()的值转换成字符串，并插入到"%1"这个占位符中。
     * 这样做可以确保字符串的格式正确，特别是当需要插入变量时。 */

    // 积分写入历史战绩中
    QFile file("D:/SHIMIR/Documents/SnakesGame/history.txt"); // 将积分放入进 history.txt 文件中，第二界面的历史战绩读取文件

    int c = snakeList.size();                                   // 得到蛇链表的长度
    if(file.open(QIODevice::WriteOnly | QIODevice::ReadWrite))
    {
        QTextStream out(&file);
        int num = c - 3;                                    // 得到的积分为蛇链长度减去起始蛇的长度
        out << num;
        qDebug() << num;
        file.close();                                   // 记得关闭文件
    }

    //绘制游戏失败效果
    if(checkFail())
    {
        pen.setColor(Qt::red);
        painter.setFont(qfont);
        painter.setPen(pen);
        painter.drawText(this->width() * 0.4,this->height() * 0.5,QString("GAME OVER!"));
        /* 游戏失败是我们在游戏进行时出现的问题，游戏进行时，我们需要定时器来执行蛇的移动 */
        /* 这里咱不用理解，只是提前写在了这个位置 */
        /* 同理sound的写法也是，是为了停止游戏进行时出现的音乐 */
        timer->stop();                          //
        QSound::play(":res/gameover.wav");//会不时响起


        qDebug() << sound;
        qDebug() << " gameover!!!1 ";
        sound->stop();
    }
}

bool GameRoom::checkFail()
{
    for(int i = 0; i < snakeList.size(); i++)
    {
        for(int j = i + 1; j <snakeList.size(); j++)
        {
            if(snakeList.at(i) == snakeList.at(j))
            {
                qDebug() << "游戏检测失败";
                return true;
            }
        }
    }
    return false;
}

void GameRoom::moveUp()
{
    QPointF leftTop;
    QPointF rightBottom;

    auto snakeHead = snakeList.front();
    int headX = snakeHead.x();
    int headY = snakeHead.y();

    if(headY < ksnakeNodeHeight)
    {
        leftTop = QPointF(headX,this->height() - ksnakeNodeHeight);
    }
    else
    {
        leftTop = QPointF(headX,headY - ksnakeNodeHeight);
    }
    rightBottom = leftTop + QPointF(ksnakeNodeWidth,ksnakeNodeHeight);

    snakeList.push_front(QRectF(leftTop,rightBottom));
}

void GameRoom::moveDown()
{
    QPointF leftTop;
    QPointF rightBottom;

    auto snakeHead = snakeList.front();
    int headX = snakeHead.x();
    int headY = snakeHead.y();

    if(headY + ksnakeNodeHeight * 2 > this->height())
    {
        leftTop = QPointF(headX,0);
    }
    else
    {
        //leftTop = QPointF(headX,headY + ksnakeNodeHeight);
        leftTop = snakeHead.bottomLeft();
    }
    rightBottom = leftTop + QPointF(ksnakeNodeWidth,ksnakeNodeHeight);
    snakeList.push_front(QRectF(leftTop,rightBottom));
}

void GameRoom::moveLeft()
{
    QPointF leftTop;
    QPointF rightBottom;

    auto snakeHead = snakeList.front();
    int headX = snakeHead.x();
    int headY = snakeHead.y();

    if(headX - ksnakeNodeWidth < 0)
    {
        leftTop = QPointF(1000 - ksnakeNodeWidth,headY);
    }
    else
    {
        leftTop = QPointF(headX - ksnakeNodeWidth,headY);

    }
    rightBottom = leftTop + QPointF(ksnakeNodeWidth,ksnakeNodeHeight);
    snakeList.push_front(QRectF(leftTop,rightBottom));
}

void GameRoom::moveRight()
{
    QPointF leftTop;
    QPointF rightBottom;

    auto snakeHead = snakeList.front();
    int headX = snakeHead.x();
    int headY = snakeHead.y();

    if(headX + ksnakeNodeWidth > 980)
    {
        leftTop = QPointF(0,headY);
    }
    else
    {
        //leftTop = QPointF(headX,headY + ksnakeNodeHeight);
        leftTop = snakeHead.topRight();
    }
    rightBottom = leftTop + QPointF(ksnakeNodeWidth,ksnakeNodeHeight);
    snakeList.push_front(QRectF(leftTop,rightBottom));
}

void GameRoom::createNewFood()
{
    foodNode = QRectF(qrand() % (1000/ksnakeNodeWidth) * ksnakeNodeWidth,
                      qrand() % (this->height()/ksnakeNodeHeight) * ksnakeNodeHeight,
                      ksnakeNodeWidth,
                      ksnakeNodeHeight);
}

